<template>
  <div class="main">
    <div>
      <div>
        <div> 贪吃蛇小游戏</div>
        <div><el-button :disabled="gaming" type="primary" @click="startGame">开始游戏</el-button></div>
        <div>分数：{{ score }}</div>
      </div>

      <div>
        <div class="div_canvas" ref="div_canvas"></div>
      </div>
    </div>
  </div>
  <!-- 排行榜 -->
  <div class="rank-box">
    <GameRankComp game="snake"></GameRankComp>
  </div>

  <BackToHome></BackToHome>
</template>
<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount } from 'vue'
import { log } from '../../ts/logger'
import { SnakeBody } from '../../ts/types/Game'
import { BaseResult } from '../../ts/types/BaseResult'
import { ApiService as api } from '../../ts/ApiService'

import BackToHome from '../../components/BackToHomeComp.vue'

const score = ref(0)
const canvas_width = 600
const canvas_height = 400
const body_size = 20
const div_canvas = ref<HTMLDivElement>()
const canvas = ref<HTMLCanvasElement>()
import GameRankComp from '../../components/GameRankComp.vue'
let ctx: CanvasRenderingContext2D
let speed = ref(250)

//#region 排行榜信息
const updateScore = () => {
  api.put('/games/snake', { score: score.value }, (data: BaseResult) => {
    log.debug('更新记录：', data)
  })
}
//#endregion

//#region 游戏相关
const paused = ref(false)
const timer = ref<number>(0)
const gaming = ref(false)
const startGame = () => {
  if (gaming.value || paused.value) {
    return
  }
  score.value = 0
  gaming.value = true
  direction.value = 'right'
  log.debug('开始游戏')
  if (timer.value) {
    clearInterval(timer.value)
  }
  snake.value.length = 0
  initSnake()
  drawBackground()
  drawSnake(snake.value)

  timer.value = setInterval(moveSnake, speed.value)
}

const checkGame = () => {
  log.debug('检查游戏')
  if (paused.value) {
    return
  }
  if (snake.value[0].x < 0 || snake.value[0].x >= canvas_width || snake.value[0].y < 0 || snake.value[0].y >= canvas_height) {
    log.debug('游戏结束')
    gaming.value = false
    clearInterval(timer.value)
    updateScore()
    return
  }
  for (let i = 1; i < snake.value.length; i++) {
    if (snake.value[0].x === snake.value[i].x && snake.value[0].y === snake.value[i].y) {
      log.debug('游戏结束')
      gaming.value = false
      clearInterval(timer.value)
      updateScore()
      return
    }
  }
}

const checkFood = () => {
  log.debug('检查食物')
  if (snake.value[0].x === food.value.x && snake.value[0].y === food.value.y) {
    log.debug('吃到食物')
    score.value++
    snake.value.push(makeBody(snake.value[0].x, snake.value[0].y))
    foodHaving.value = false
    makeFood()
  }
}

const food = ref<SnakeBody>({ x: 0, y: 0 } as SnakeBody)
const foodHaving = ref(false)

const checkFoodPositon = () => {
  if (snake.value.some((body) => body.x === food.value.x && body.y === food.value.y)) {
    return false
  }
  return true
}

const makeFood = () => {
  log.debug('生成食物')
  if (foodHaving.value) {
    return
  }
  do {
    const x = Math.floor(Math.random() * (canvas_width / body_size)) * body_size
    const y = Math.floor(Math.random() * (canvas_height / body_size)) * body_size
    food.value = makeBody(x, y)
    if (checkFoodPositon()) {
      foodHaving.value = true
      break
    }
  } while (true)
}
//#endregion

//#region 数据相关
const snake = ref<Array<SnakeBody>>([])
const direction = ref<string>('right')

const drawGame = () => {
  drawBackground()
  drawSnake(snake.value)
  if (foodHaving.value) {
    drawBody(food.value, true)
  }
}

const moveSnake = () => {
  if (paused.value) {
    return
  }
  log.debug('移动')
  if (direction.value === 'right') {
    snake.value.unshift(makeBody(snake.value[0].x + body_size, snake.value[0].y))
    snake.value.pop()
  } else if (direction.value === 'left') {
    snake.value.unshift(makeBody(snake.value[0].x - body_size, snake.value[0].y))
    snake.value.pop()
  } else if (direction.value === 'up') {
    snake.value.unshift(makeBody(snake.value[0].x, snake.value[0].y - body_size))
    snake.value.pop()
  } else if (direction.value === 'down') {
    snake.value.unshift(makeBody(snake.value[0].x, snake.value[0].y + body_size))
    snake.value.pop()
  }
  drawGame()
  checkGame()
  checkFood()
}

const makeBody = (x: number, y: number): SnakeBody => {
  return { x: x, y: y, width: body_size, height: body_size } as SnakeBody
}

const initSnake = () => {
  log.debug('初始化蛇')
  snake.value = [makeBody(80, 20), makeBody(60, 20), makeBody(40, 20), makeBody(20, 20)]
}

const onKeyup = (event: KeyboardEvent) => {
  log.debug('按键抬起', event.key)
  if (!gaming.value) {
    return
  }

  if(event.key==' ') {
    paused.value = !paused.value
  }
  if (paused.value) {
    log.debug("游戏暂停中。。。")
    return
  }
  switch (event.key) {
    case 'ArrowUp':
    case 'w':
      if (direction.value === 'down') {
        return
      }
      direction.value = 'up'
      moveSnake()
      break
    case 'ArrowDown':
    case 's':
      if (direction.value === 'up') {
        return
      }
      direction.value = 'down'
      moveSnake()
      break
    case 'ArrowLeft':
    case 'a':
      if (direction.value === 'right') {
        return
      }
      direction.value = 'left'
      moveSnake()
      break
    case 'ArrowRight':
    case 'd':
      if (direction.value === 'left') {
        return
      }
      direction.value = 'right'
      moveSnake()
      break
  }
}
//#endregion

//#region 绘制相关
const drawBackground = () => {
  log.debug('绘制背景')
  ctx?.clearRect(0, 0, canvas_width, canvas_height)
}

const drawBody = (body: SnakeBody, food: boolean = false) => {
  log.debug('绘制身体', body)
  ctx.strokeStyle = food ? '#0000ff' : '#ff0000'
  ctx.strokeRect(body.x, body.y, body.width, body.height)
}

const drawSnake = (bodys: Array<SnakeBody>) => {
  log.debug('绘制蛇')
  bodys.forEach((body) => {
    drawBody(body)
  })
}

//#endregion

//#region 初始化canvas
const createCanvas = () => {
  if (div_canvas.value) {
    canvas.value = document.createElement('canvas')
    canvas.value.setAttribute('width', canvas_width + 'px')
    canvas.value.setAttribute('height', canvas_height + 'px')
    ctx = canvas.value.getContext('2d') as CanvasRenderingContext2D
    div_canvas.value.appendChild(canvas.value)
  }
}

onBeforeUnmount(() => {
  log.debug('销毁canvas元素')
  canvas.value?.remove()
  document.removeEventListener('keyup', onKeyup)
  if (timer.value) {
    clearInterval(timer.value)
  }
})

onMounted(() => {
  document.addEventListener('keyup', onKeyup)
  createCanvas()
  initSnake()
  drawBackground()
  drawSnake(snake.value)
  makeFood()
  log.debug('canvas元素：', div_canvas.value, canvas.value)
})

//#endregion
</script>

<style lang="scss" scoped>
.main {
  display: flex;
  justify-content: center;
  > div {
    > div:nth-of-type(1) {
      text-align: center;
      font-size: 1.5rem;
      padding: 1rem;
    }
    > div:nth-of-type(2) {
      padding: 1rem;
      border-radius: 0.5rem;
      border: 1px solid #ccc;
    }
  }
}
.div_canvas {
  width: 600px;
  height: 400px;
  border: 1px solid #ccc;
}
.rank-box {
  position: fixed;
  right: 1rem;
  top: 1rem;
}
</style>
